// Caching main content
var $content = $('#contentmain');

/**
 * Bot constructor
 */
var Bot = function() {
	var active = true,		// Active flag
		debug = false,		// Debug flag
		last,				// Last timer value
		lastArena,			// Last arena time
		currentPage,		// Current page handler
		justStarted = true,	// Just started flag
		log = [],			// Bot log
		mode = 'battle',	// Bot mode (@TODO)
		lastMode,
		moveToCoords,
		playerID = $('#mcname').text();
	
	return {
		/**
		 * Start bot
		 * Triggers "bot-start" event
		 */
		start : function() {
			active = true;
			justStarted = true;
			$(this).trigger('bot-start');
			
			this.next();

			justStarted = false;
			
			return this;
		},
		
		/**
		 * Stop bot
		 * Triggers "bot-stop" event
		 */
		stop : function() {
			active = false;
			$(this).trigger('bot-stop');
			
			return this;
		},
		
		/**
		 * Toggle bot state
		 */
		toggle : function() {
			active ? this.stop() : this.start();
			
			return this;
		},
		
		/**
		 * Next bot frame
		 */
		next : function() {
			if (!active) {
				return this;
			}
			
			// Need to monitor chat on each tick
			//this.chatMonitor();
		
			var current = $('#actiontimer').text(),
				self = this;

			isNaN(current) && (current = -1);
			
			if (justStarted || (last != current)) {
				if (+last < +current) {
					this.loaded();
				}
				
				if (current == '0.0') {
					this.ready();
				}
			}
			
			last = current;
			
			setTimeout(function() {
				self.next();
			}, 200);
			
			return this;
		},
		
		/**
		 * Try to define current page and execute its "loaded" handler
		 */
		loaded : function() {
			$(this).trigger('page-loaded');
			
			this.debug('loaded');
			
			this.definePage();
			
			currentPage && currentPage.loaded && currentPage.loaded();
			
			return this;
		},
		
		/**
		 * Try to execute "ready" handler for the current page
		 */
		ready : function() {
			$(this).trigger('page-ready');
			
			this.debug('ready');
			
			if (this.getCurrentMode() == 'move') {
				this.nextMove();
			
				return this;
			}
			
			!currentPage || !currentPage.check() && this.definePage();
			
			currentPage && currentPage.ready && currentPage.ready();
			
			return this;
		},
		
		/**
		 * Tell the bot to move to designated position on map
		 *
		 * @param {Number} x X position
		 * @param {Number} y Y position
		 */
		moveTo : function(x, y) {
			moveToCoords = {x : +x || 0, y : +y || 0};
			
			this.setMode('move');
			
			return this;
		},
		
		/**
		 * Stop moving and restore last mode
		 */
		stopMove : function() {
			this.restoreLastMode();
			
			return this;
		},
		
		/**
		 * Do the next move on map if we didn't reach the destination yet.
		 */
		nextMove : function() {
			var currentCoords = $('#loccoords').text().split(',');
			
			if (!moveToCoords) {
				return this;
			}
			
			if (currentCoords[0] == moveToCoords.x && currentCoords[1] == moveToCoords.y) {
				this.setMode('battle');
			}
			else if (currentCoords[0] != moveToCoords.x) {
				this.proxyCall('go', (currentCoords[0] < moveToCoords.x) ? 3 : 4);
			}
			else if (currentCoords[1] != moveToCoords.y) {
				this.proxyCall('go', (currentCoords[1] < moveToCoords.y) ? 1 : 2);
			}
			
			return this;
		},
		
		/**
		 * Call a native game function by proxy
		 *
		 * @param {String} [functionName] Name of game function to be called
		 * @param [args...] Any amount of arguments; all will be passed to function call
		 */
		proxyCall : function() {
			var args = Array.prototype.slice.call(arguments);
			
			this.proxyCallRaw(args.shift() + '("' + args.join('", "') + '")');
			
			return this;
		},
		
		/**
		 * Call a native game function by proxy
		 *
		 * @param {String} func Expression to be called
		 */
		proxyCallRaw : function(func) {
			$('#proxy-btn').attr('onclick', func.replace('javascript:', ''))[0].click();
			
			return this;
		},
		
		/**
		 * Chat monitoring actions
		 */
		chatMonitor : function() {
			var self = this;
			
			$('span:contains("Global"):not(.viewed)', '#chat').each(function(index, msg) {
				var $msg = $(msg),
					msgText = $msg.text();
				
				// Player related globals
				if (msgText.indexOf(playerID) >= 0) {
					// Prize Pouch found
					if (msgText.indexOf('Prize Pouch') >= 0) {
						self
							.log('global', 'Prize pouch found')
							.setStat('loot-main-pouches', 1);
					}
					// Achivements
					else if (msgText.indexOf('has been awarded') >= 0) {
						self.log('global', msgText);
					}
					else {
						self.log('global', msgText);
					}
				}
				// Non-player related globals
				else {
					/*
					<span style="color: #33FFFF"><b>Event</b>: A fearsome LostShadowMaster has been spotted at (289,393) and a reward of 4,000 platinum will be awarded to the player that lands the final blow. A further 40,000 platinum will be distributed to everyone who helps to take it down.</span>
					*/
				}
			
				$msg.addClass('viewed');
			});
		},
		
		/**
		 * Define current page and cache it
		 */
		definePage : function() {
			for (var i in Pages) {
				if (Pages[i].check && Pages[i].check()) {
					currentPage = Pages[i];
					
					break;
				}
			}
			
			return this;
		},
		
		/**
		 * Put items to the console if "debug" flag is set
		 *
		 * @param [args...] Any amount of arguments, all will be printed to console
		 */
		debug : function() {
			var args = Array.prototype.slice.call(arguments);
			args.unshift(new Date);
		
			debug && console.log.apply(console, args);
			
			return this;
		},
		
		/**
		 * Put a message to bot log
		 * If 1 argument given, it will be used as message
		 * If 2 arguments given, then first will be a category identifier, and the second is a message
		 */
		log : function() {
			var category = arguments.length == 1 ? 'general' : arguments[0],
				msg = arguments.length == 1 ? arguments[0] : arguments[1];
		
			log.push({
				date : new Date,
				category : category,
				msg : msg
			});
			
			return this;
		},
		
		/**
		 * Set stat value
		 *
		 * @param stat ID of element in bot stats panel
		 * @param value Value modifier
		 */
		setStat : function(stat, value) {
			var $fld = $('#' + stat),
				oldValue;
			
			if ($fld.size()) {
				oldValue = $fld.text().replace(/\D+/g, '');
				value = (+value) + (+oldValue);
				
				$fld.text(this.format(value));
			}
			
			return this;
		},
		
		/**
		 * Return bot "active" flag value
		 */
		isActive : function() {
			return active;
		},
		
		/**
		 * Format numeric value by adding commas
		 *
		 * @param {Number} value Input value
		 * 
		 * @returns {Number} Formatted value
		 */
		format : function(value) {
			value = value.toString().replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, '\$1,');

			return value;
		},
		
		/**
		 * Return bot log
		 *
		 * @returns {Array} Bot log
		 */
		getLog : function() {
			return log;
		},
		
		/**
		 * Get current mode
		 *
		 * @returns {String} Current mode
		 */
		getCurrentMode : function() {
			return mode;
		},
		
		/**
		 * Set new mode
		 *
		 * @param {String} newMode New mode ID
		 */
		setMode : function(newMode) {
			lastMode = mode;
			mode = newMode;
			
			return this;
		},
		
		/**
		 * Restore the last mode of the bot
		 */
		restoreLastMode : function() {
			mode = lastMode || 'battle';
			
			return this;
		},
		
		/**
		 * Check if bot is ready for new arena
		 */
		isReadyForArena : function() {
			var now = new Date;
			
			return !lastArena || (lastArena.getHour() != now.getHour());
		},
		
		/**
		 * Set arena last enter time
		 */
		setNewArenaTime : function() {
			lastArena = new Date;
			
			return this;
		}
	};
};

var bot = Bot();

$(bot).bind('page-ready', function() {
	
});

/* ************************************************ */

bot.start();

/* ******************* UTILS ********************** */

Date.prototype.format = function(format) {
	var now = this;
	
	return format.replace(/%(\w)/g, function(match, placeholder) {
		var value;
		
		switch (placeholder) {
			case 'd':
				value = now.getDate();
				(value < 10) && (value = '0' + value);
				break;
			case 'm':
				value = now.getMonth() + 1;
				(value < 10) && (value = '0' + value);
				break;
			case 'Y':
				value = now.getFullYear();
				break;
			case 'H':
				value = now.getHours();
				(value < 10) && (value = '0' + value);
				break;
			case 'i':
				value = now.getMinutes();
				(value < 10) && (value = '0' + value);
				break;
			case 's':
				value = now.getSeconds();
				(value < 10) && (value = '0' + value);
				break;
		}
		
		return value;
	});
}